<?php

class BidModel extends CFormModel
{

    const ACTION_COST = 'COST';

    const ACTION_EARN = 'EARN';

    const LOOP_INTERVAL = 500000;

    public $bid_source_type;

    public $bid_type;

    public $action;

    public $note;

    public $customer_id;

    public $auction_id;

    public $timeOutLeft = 0;

    protected $_amount = 0;

    protected $_transaction = false;

    protected $_lastHistoryId = 0;

    protected $_env = array();

    public function setEnv($env, $on = true)
    {
        $this->_env[$env] = $on;
        return $this;
    }

    public function isEnv($env)
    {
        return array_key_exists($env, $this->_env) && $this->_env[$env];
    }

    public function primaryKey()
    {
        return $this->customer_id . ':' . $this->bid_type;
    }

    public function setAmount($amount)
    {
        if ($amount < 0) {
            $this->action = self::ACTION_COST;
        } else {
            $this->action = self::ACTION_EARN;
        }
        return $this->_amount = $amount;
    }

    public function getAmount()
    {
        return $this->_amount;
    }

    protected $_componentMapper = array();

    public function componentMapper()
    {
        return array(
            'auctionCost' => array(
                'class' => 'dao.bidAuction.component.BidAuctionCost'
            ),
            'bidExpire' => array(
                'class' => 'dao.bid.component.BidExpire'
            )
        );
    }

    public function component($componentName)
    {
        $componentMapper = $this->componentMapper();
        if (! array_key_exists($componentName, $this->_componentMapper)) {
            $className = Yii::import($componentMapper[$componentName]['class']);
            $classObj = new $className();
            $classObj->setPrototype($this);
            $this->_componentMapper[$componentName] = $classObj;
        }
        return $this->_componentMapper[$componentName];
    }

    public function rules()
    {
        return array(
            array(
                'customer_id',
                'exist',
                'attributeName' => 'customer_id',
                'className' => 'CustomerBidInfo'
            ),
            array(
                'bid_source_type,bid_type,action,note,amount',
                'safe'
            )
        );
    }

    public function getBid()
    {
        $bidNumSQL = '
            SELECT
                customer_bid_info.bid_num AS bid_num
            FROM
                customer_bid_info
            WHERE
                customer_bid_info.primary_key = "' . $this->primaryKey() . '"
        ';
        $bidNum = Yii::app()->db->createCommand($bidNumSQL)->queryRow();
        return ! empty($bidNum['bid_num']) ? $bidNum['bid_num'] : 0;
    }

    public function setBid($amount, $source, $note = null)
    {
        $this->setAmount($amount);
        $this->bid_source_type = $source;
        $this->note = $note;
        
        $timeOut = time() + $this->timeOutLeft;
        $bidReturn = true;
        do {
            $retry = time() < $timeOut;
//             if (Yii::app()->lock->get('SET_BID_EVENT:'.$this->customer_id)) {
//                 usleep(self::LOOP_INTERVAL);
//                 continue;
//             }
            
            
            $scenario = $this->getScenario();
            if (! $this->isEnv('parentTransaction')) {
                $transaction = Yii::app()->db->beginTransaction();
            }
            
            try {
                $this->updateBidInfo()->addHistory();
                if (! $this->isEnv('bidExpire')){
                    $this->component('bidExpire')->run(7776000);
                }
                
                if (! $this->isEnv('parentTransaction')) {
                    $transaction->commit();
                }
                return true;
            } catch (Exception $e) {
            	var_dump($e->getMessage());
                $retry = false;
                if (! $this->isEnv('parentTransaction')) {
                    $transaction->rollback();
                }
                if ($this->isEnv('throw')) {
                    throw new CException(Yii::t('yii', $e->getMessage()));
                }
                return false;
            } finally{
//                 Yii::app()->->lock->del('SET_BID_EVENT:' . $this->customer_id);
            }
        } while ($retry);
        $this->addError('time_out', 'Bid Time Out');
        if ($this->isEnv('throw')) {
            throw new CException(Yii::t('yii', 'Bid Time Out'));
        }
        return false;
    }

    public function updateBidInfo()
    {
        $bids = $this->getAmount();
        
        $bidSQL = '
            INSERT INTO
                customer_bid_info
            VALUES (
                "' . $this->primaryKey() . '",
                "' . $this->customer_id . '",
                "' . $this->bid_type . '",
                @bid_amount := ' . $bids . '
            )
            ON DUPLICATE KEY UPDATE
                customer_bid_info.bid_num =  @bid_amount := customer_bid_info.bid_num + ' . $bids . '
        ';
        $updateInfoBid = Yii::app()->db->createCommand($bidSQL)->execute();
        $updateAfterBidSQL = 'select @bid_amount as bid_amount';
        $updateAfterBid = Yii::app()->db->createCommand($updateAfterBidSQL)->queryRow();
        if ($updateAfterBid['bid_amount'] < 0) {
            $this->addError('update_bid', 'Update Bid Info Bid Negative');
            throw new CException(Yii::t('yii', 'Update Bid Info Bid Negative'));
        }
        
        return $this;
    }

    public function addHistory()
    {
        $tablename = Method::getBidHistoryUserTableName($this->customer_id);
        $bidhistory = new BidHistory($tablename);
        $bidhistory->attributes = array(
            'amount' => $this->amount,
            'bid_source_type' => $this->bid_source_type,
            'customer_id' => $this->customer_id,
            'bid_type' => $this->bid_type,
            'action' => $this->action,
            'note' => $this->note,
            'auction_id' => $this->auction_id,
        );
        $bidhistory->created= time();
        $addHistory = $bidhistory->save();
        if (! $addHistory) {
            $this->addErrors($bidhistory->getErrors());
            throw new CException(Yii::t('yii', 'Add History Error ' . json_encode($bidhistory->getErrors())));
        }
        $this->_lastHistoryId = $bidhistory->id;
        return $this;
    }

    public function getLastHistoryId()
    {
        return $this->_lastHistoryId;
    }
}